import os
import datetime
import random
import string
import hashlib
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify, session
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from flask_mail import Mail, Message
from werkzeug.security import generate_password_hash, check_password_hash
from itsdangerous import URLSafeTimedSerializer
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

app = Flask(__name__)

# 配置
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'dev_key_for_testing')

# 使用SQLite数据库
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# 邮件配置
app.config['MAIL_SERVER'] = 'smtp.gmail.com'  # 使用Gmail的SMTP服务器
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = os.getenv('MAIL_USERNAME', 'your-email@gmail.com')
app.config['MAIL_PASSWORD'] = os.getenv('MAIL_PASSWORD', 'your-app-password')  # 对于Gmail，需要使用应用专用密码
app.config['MAIL_DEFAULT_SENDER'] = os.getenv('MAIL_DEFAULT_SENDER', 'your-email@gmail.com')

# 初始化扩展
db = SQLAlchemy(app)
mail = Mail(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
login_manager.login_message = '请先登录以访问此页面'
login_manager.login_message_category = 'error'

# 用于生成安全令牌
ts = URLSafeTimedSerializer(app.config["SECRET_KEY"])

# 定义数据模型
class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(100), unique=True, nullable=False)
    password_hash = db.Column(db.String(200), nullable=False)
    nickname = db.Column(db.String(50), default='用户')
    avatar = db.Column(db.String(200), default='https://www.gravatar.com/avatar/00000000000000000000000000000000?d=mp&f=y')
    bio = db.Column(db.Text, default='这个人很懒，什么都没有留下。')
    is_active = db.Column(db.Boolean, default=False)
    created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
    posts = db.relationship('Post', backref='author', lazy=True)
    
    def set_password(self, password):
        self.password_hash = generate_password_hash(password)
        
    def check_password(self, password):
        return check_password_hash(self.password_hash, password)
    
    def get_avatar(self, size=80):
        # 使用本地头像文件
        if not self.avatar or self.avatar.startswith('https://www.gravatar.com'):
            # 默认使用第一个头像
            return '/static/resources/生成头像.png'
        return self.avatar
    
    def __repr__(self):
        return f'<User {self.email}>'

class VerificationCode(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(100), nullable=False)
    code = db.Column(db.String(6), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
    
    def __repr__(self):
        return f'<VerificationCode for {self.email}>'

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    content = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True)  # 允许为空以兼容现有数据
    comments = db.relationship('Comment', backref='post', lazy=True, cascade='all, delete-orphan')
    views = db.relationship('ViewHistory', backref='post', lazy=True)
    
    @property
    def author_name(self):
        if self.author:
            return self.author.nickname or self.author.email.split('@')[0]
        return 'Unknown'

    def __repr__(self):
        return f'<Post {self.title}>'

class Comment(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.Text, nullable=False)
    author = db.Column(db.String(100), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True)  # 允许为空以兼容现有数据
    
    @property
    def author_name(self):
        if self.user_id:
            user = User.query.get(self.user_id)
            if user:
                return user.nickname or user.email.split('@')[0]  # 优先使用昵称
        return "匿名用户"

    def __repr__(self):
        return f'<Comment by {self.author}>'

class ViewHistory(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
    viewed_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
    
    user = db.relationship('User', backref=db.backref('view_history', lazy='dynamic'))
    
    def __repr__(self):
        return f'<ViewHistory {self.user_id} viewed {self.post_id} at {self.viewed_at}>'

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

# 生成验证码
def generate_verification_code():
    return ''.join(random.choices(string.digits, k=6))

# 发送验证码邮件
def send_verification_email(email, code):
    # 开发环境下，可以选择打印验证码而不是真正发送邮件
    if os.getenv('FLASK_ENV') == 'development' or os.getenv('MAIL_USERNAME') == 'your-email@gmail.com':
        print(f"[开发模式] 发送验证码到 {email}: {code}")
        return
    
    # 生产环境下，真正发送邮件
    msg = Message("您的验证码", recipients=[email])
    msg.body = f"您的验证码是: {code}，有效期为10分钟。"
    mail.send(msg)

# 路由：用户认证
@app.route('/register', methods=['GET', 'POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    
    if request.method == 'POST':
        email = request.form.get('email')
        password = request.form.get('password')
        confirm_password = request.form.get('confirm_password')
        verification_code = request.form.get('verification_code')
        
        # 验证表单数据
        if not email or not password or not confirm_password or not verification_code:
            flash('所有字段都是必填的', 'error')
            return redirect(url_for('register'))
        
        if password != confirm_password:
            flash('两次输入的密码不匹配', 'error')
            return redirect(url_for('register'))
        
        # 检查用户是否已存在
        existing_user = User.query.filter_by(email=email).first()
        if existing_user:
            flash('该邮箱已被注册', 'error')
            return redirect(url_for('register'))
        
        # 验证验证码
        verification = VerificationCode.query.filter_by(email=email, code=verification_code).order_by(VerificationCode.created_at.desc()).first()
        if not verification:
            flash('验证码无效', 'error')
            return redirect(url_for('register'))
        
        # 检查验证码是否过期（10分钟）
        now = datetime.datetime.utcnow()
        if (now - verification.created_at).total_seconds() > 600:
            flash('验证码已过期', 'error')
            return redirect(url_for('register'))
        
        # 创建新用户
        user = User(email=email, is_active=True)
        user.set_password(password)
        db.session.add(user)
        db.session.commit()
        
        # 删除验证码
        db.session.delete(verification)
        db.session.commit()
        
        flash('注册成功！请登录', 'success')
        return redirect(url_for('login'))
    
    return render_template('register.html', now=datetime.datetime.now())

@app.route('/send-verification-code', methods=['POST'])
def send_verification_code():
    email = request.form.get('email')
    
    if not email:
        return jsonify({'success': False, 'message': '请提供邮箱地址'})
    
    # 生成验证码
    code = generate_verification_code()
    
    # 保存验证码到数据库
    verification = VerificationCode(email=email, code=code)
    db.session.add(verification)
    db.session.commit()
    
    # 发送验证码邮件
    try:
        send_verification_email(email, code)
        
        # 如果是开发模式，返回验证码信息
        if os.getenv('FLASK_ENV') == 'development' or os.getenv('MAIL_USERNAME') == 'your-email@gmail.com':
            return jsonify({
                'success': True, 
                'message': f'开发模式：验证码是 {code}（已保存到数据库，无需真正发送邮件）'
            })
        
        return jsonify({'success': True, 'message': '验证码已发送到您的邮箱'})
    except Exception as e:
        db.session.delete(verification)
        db.session.commit()
        error_message = str(e)
        
        # 提供更友好的错误信息
        if 'getaddrinfo failed' in error_message:
            error_message = '无法连接到邮件服务器，请检查网络连接和邮件服务器配置'
        
        return jsonify({'success': False, 'message': f'发送邮件失败: {error_message}'})

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    
    if request.method == 'POST':
        email = request.form.get('email')
        password = request.form.get('password')
        remember = request.form.get('remember') == 'on'
        
        if not email or not password:
            flash('请输入邮箱和密码', 'error')
            return redirect(url_for('login'))
        
        user = User.query.filter_by(email=email).first()
        
        if not user or not user.check_password(password):
            flash('邮箱或密码错误', 'error')
            return redirect(url_for('login'))
        
        if not user.is_active:
            flash('账户未激活', 'error')
            return redirect(url_for('login'))
        
        login_user(user, remember=remember)
        next_page = request.args.get('next')
        
        flash('登录成功！', 'success')
        return redirect(next_page or url_for('index'))
    
    return render_template('login.html', now=datetime.datetime.now())

@app.route('/logout')
def logout():
    logout_user()
    flash('您已成功登出', 'success')
    return redirect(url_for('index'))

@app.route('/profile')
@login_required
def profile():
    # 获取用户发布的文章
    user_posts = Post.query.filter_by(user_id=current_user.id).order_by(Post.created_at.desc()).all()
    
    # 获取用户浏览过的文章
    viewed_posts_history = ViewHistory.query.filter_by(user_id=current_user.id).order_by(ViewHistory.viewed_at.desc()).all()
    viewed_posts = []
    
    # 去重，只保留最近的浏览记录
    post_ids = set()
    for history in viewed_posts_history:
        if history.post_id not in post_ids:
            post_ids.add(history.post_id)
            viewed_posts.append({
                'post': Post.query.get(history.post_id),
                'viewed_at': history.viewed_at
            })
    
    return render_template('profile.html', user=current_user, user_posts=user_posts, viewed_posts=viewed_posts, now=datetime.datetime.now())

@app.route('/profile/edit', methods=['GET', 'POST'])
@login_required
def edit_profile():
    if request.method == 'POST':
        nickname = request.form.get('nickname')
        bio = request.form.get('bio')
        avatar = request.form.get('avatar')
        
        if nickname:
            current_user.nickname = nickname
        if bio:
            current_user.bio = bio
        if avatar:
            current_user.avatar = avatar
            
        db.session.commit()
        flash('个人资料已更新', 'success')
        return redirect(url_for('profile'))
        
    return render_template('edit_profile.html', user=current_user, now=datetime.datetime.now())

# 路由：博客功能
@app.route('/')
def index():
    posts = Post.query.order_by(Post.created_at.desc()).all()
    return render_template('index.html', posts=posts, now=datetime.datetime.now())

@app.route('/post/<int:post_id>')
def view_post(post_id):
    post = Post.query.get_or_404(post_id)
    
    # 如果用户已登录，记录浏览历史
    if current_user.is_authenticated:
        # 检查是否已经有浏览记录
        existing_view = ViewHistory.query.filter_by(
            user_id=current_user.id,
            post_id=post_id
        ).first()
        
        if existing_view:
            # 更新浏览时间
            existing_view.viewed_at = datetime.datetime.utcnow()
        else:
            # 创建新的浏览记录
            view_history = ViewHistory(user_id=current_user.id, post_id=post_id)
            db.session.add(view_history)
        
        db.session.commit()
    
    return render_template('post.html', post=post, now=datetime.datetime.now())

@app.route('/post/new', methods=['GET', 'POST'])
@login_required
def new_post():
    if request.method == 'POST':
        title = request.form.get('title')
        content = request.form.get('content')
        
        if not title or not content:
            flash('标题和内容不能为空', 'error')
            return redirect(url_for('new_post'))
        
        post = Post(title=title, content=content, author=current_user)
        db.session.add(post)
        db.session.commit()
        
        flash('文章发布成功！', 'success')
        return redirect(url_for('view_post', post_id=post.id))
    
    return render_template('create_post.html', now=datetime.datetime.now())

@app.route('/post/<int:post_id>/edit', methods=['GET', 'POST'])
@login_required
def edit_post(post_id):
    post = Post.query.get_or_404(post_id)
    
    # 检查是否是文章作者
    if post.user_id and post.user_id != current_user.id:
        flash('您没有权限编辑此文章', 'error')
        return redirect(url_for('view_post', post_id=post.id))
    
    if request.method == 'POST':
        title = request.form.get('title')
        content = request.form.get('content')
        
        if not title or not content:
            flash('标题和内容不能为空', 'error')
            return redirect(url_for('edit_post', post_id=post.id))
        
        post.title = title
        post.content = content
        post.updated_at = datetime.datetime.utcnow()
        db.session.commit()
        
        flash('文章更新成功！', 'success')
        return redirect(url_for('view_post', post_id=post.id))
    
    return render_template('edit_post.html', post=post, now=datetime.datetime.now())

@app.route('/post/<int:post_id>/delete', methods=['POST'])
@login_required
def delete_post(post_id):
    post = Post.query.get_or_404(post_id)
    
    # 检查是否是文章作者
    if post.user_id and post.user_id != current_user.id:
        flash('您没有权限删除此文章', 'error')
        return redirect(url_for('view_post', post_id=post.id))
    
    db.session.delete(post)
    db.session.commit()
    
    flash('文章已删除', 'success')
    return redirect(url_for('index'))

@app.route('/post/<int:post_id>/comment', methods=['POST'])
def add_comment(post_id):
    post = Post.query.get_or_404(post_id)
    content = request.form.get('content')
    
    if current_user.is_authenticated:
        author = current_user.email
        user_id = current_user.id
    else:
        author = request.form.get('author')
        user_id = None
        
        if not author:
            flash('评论作者不能为空', 'error')
            return redirect(url_for('view_post', post_id=post.id))
    
    if not content:
        flash('评论内容不能为空', 'error')
        return redirect(url_for('view_post', post_id=post.id))
    
    comment = Comment(content=content, author=author, post=post, user_id=user_id)
    db.session.add(comment)
    db.session.commit()
    
    flash('评论已添加', 'success')
    return redirect(url_for('view_post', post_id=post.id))

@app.route('/api/posts')
def get_posts():
    posts = Post.query.order_by(Post.created_at.desc()).all()
    posts_data = [{
        'id': post.id,
        'title': post.title,
        'content': post.content,
        'created_at': post.created_at.isoformat(),
        'updated_at': post.updated_at.isoformat(),
        'comment_count': len(post.comments)
    } for post in posts]
    
    return jsonify(posts_data)

@app.route('/user/<username>')
def user_posts(username):
    # 查询用户，若不存在则返回404错误
    user = User.query.filter_by(username=username).first_or_404()
    
    # 获取用户发布的文章，按创建时间降序排列
    posts = Post.query.filter_by(user_id=user.id).order_by(Post.created_at.desc()).all()
    
    # 渲染用户文章页面
    return render_template('user_posts.html', user=user, posts=posts, now=datetime.datetime.now())
    
# 创建数据库表
with app.app_context():
    db.create_all()

if __name__ == '__main__':
    app.run(debug=True)